public class Expression {
	private static final int CONSTANT = 0;
	private static final int VARIABLE = 1;
	private static final int DOT_APPLICATION = 2;
	private static final int TILDE_APPLICATION = 3;

	private int type;
	private String var_name;
	private String const_value;
	private Expression[] subexpr;

	private Expression(int type, int number_of_subexpr) {
		this.type = type;
		subexpr = new Expression[number_of_subexpr];
	}

	public static Expression constant(String value) {
		Expression result = new Expression(CONSTANT, 0);
		result.const_value = value;
		return result;
	}

	public static Expression variable(String name) {
		Expression result = new Expression(VARIABLE, 0);
		result.var_name = name;
		return result;
	}

	public static Expression dotAppl(Expression sub1, Expression sub2) {
		Expression result = new Expression(DOT_APPLICATION, 2);
		result.subexpr[0] = sub1;
		result.subexpr[1] = sub2;
		return result;
	}

	public static Expression tildeAppl(Expression sub) {
		Expression result = new Expression(TILDE_APPLICATION, 1);
		result.subexpr[0] = sub;
		return result;
	}

	public Object eval() {
		Integer result = evaluate(this);
		return result;
	}

	private int evaluate(Expression e) {
		int value = 0;
		int type = e.type;

		switch (type) {
		case CONSTANT:
			value = Integer.parseInt(e.const_value);
			break;
		case VARIABLE:
			value = (Integer) Stack.getCellContentsOf(e.var_name);
			break;
		case DOT_APPLICATION:
			value = evaluate(e.subexpr[0]) + evaluate(e.subexpr[1]);
			break;
		case TILDE_APPLICATION:
			value = -evaluate(e.subexpr[0]);
			break;
		}

		return value;
	}

	public String toString() {
		return this.var_name + " " + this.const_value + " " + this.type;
	}
}
